//usr/bin/env clang++ -std=c++17 "$0" -o "$0".out && "$0".out && exit 0
//usr/bin/env true && exit -1

#include <array>
#include <type_traits>
#include <cstdint>
#include <cstddef>
#include <cstdio>

// https://stackoverflow.com/questions/77058131/is-there-any-c-c-way-for-concatenating-constant-arrays-other-than-macro
// Compile time function to add one value to an array
template <typename type_t, std::size_t N>
static constexpr void append(std::array<type_t, N> &arr, const type_t &value, std::size_t &offset) {
    arr[offset] = value;
    offset++;
}

// Compile time function to add another C array to an array
template <typename type_t, std::size_t N, std::size_t M>
static constexpr void append(std::array<type_t, N> &arr, const type_t (&values)[M], std::size_t &offset) {
    for (std::size_t n = 0; n < M; ++n, ++offset) {
        arr[offset] = values[n];
    }
}

// Compile time function to add another std::array to the array
template <typename type_t, std::size_t N, std::size_t M>
static constexpr void append(std::array<type_t, N> &arr, const std::array<type_t, M> &values, std::size_t &offset) {
    for (std::size_t n = 0; n < values.size(); ++n, ++offset) {
        arr[offset] = values[n];
    }
}

// Build a std::array from a C array
template <typename type_t, std::size_t n>
static constexpr auto array_of(const type_t (&values)[n]) {
    std::array<type_t, n> arr{};
    for (std::size_t i = 0; i < n; ++i) {
        arr[i] = values[i];
    }
    return arr;
}

// Create a variadic template function to build an array
// from a mix of values and other arrays
template <typename type_t, typename... args_t>
static constexpr auto array_of(args_t &&...args) {
    // calculate the size of the final array by summing
    // the sizes of the arguments divided by the size of the underlying type
    const auto size_v = ((sizeof(args_t) / sizeof(type_t)) + ...);
    std::array<type_t, size_v> values{};

    // start adding values at the start of the array
    std::size_t offset{0ul};

    // the compiler will select the correct append function to use at compile time
    // what you see here is a fold expression and it will "loop" over all args
    (append(values, args, offset), ...);

    return values;
}

/**
 * @brief hks blob
 */
struct HksBlob {
    uint32_t size;
    uint8_t *data;
};

/**
 * @brief hks param
 */
struct HksParam {
    uint32_t tag;
    union {
        bool boolParam;
        int32_t int32Param;
        uint32_t uint32Param;
        uint64_t uint64Param;
        struct HksBlob blob;
    };
};

extern "C" void PrintHksParams(const HksParam *p, size_t count) {
    for (size_t i = 0; i < count; ++i) {
        printf("p[%zu].tag = %u, .uint32 = %u\n", i, p[i].tag, p[i].uint32Param);
    }
}

int main() {
    constexpr auto arr1 = array_of((HksParam[]){
        {.tag = 1, .uint32Param = 2},
        {.tag = 1, .uint32Param = 2},
        {.tag = 3, .uint32Param = 4}});
    constexpr auto arr2 = array_of((HksParam[]){
        {.tag = 5, .uint32Param = 6},
        {.tag = 7, .uint32Param = 8}});
    constexpr auto arr3 = array_of<HksParam>(
        arr2);
    constexpr auto arr4 = array_of<HksParam>(
        (HksParam[]){
            {.tag = 111, .uint32Param = 111},
            {.tag = 111, .uint32Param = 111},
        },
        arr1,
        HksParam{.tag = 222, .uint32Param = 222},
        arr2,
        HksParam{.tag = 333, .uint32Param = 333},
        arr3);
    PrintHksParams(arr4.data(), arr4.size());
    return 0;
}